package com.zhouchj.elasticsearch.index;

import com.zhouchj.elasticsearch.constant.EsConstant;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexInformation;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 索引操作
 *
 * @author zhouchj
 * @date 2023/8/28
 */
@Slf4j
public class EsIndexOperate<T> {

    /**
     * 索引
     */
    private final IndexCoordinates index;

    /**
     * 索引操作
     */
    private final IndexOperations indexOperations;

    /**
     * client
     */
    private final RestHighLevelClient client;

    /**
     * 当前索引的实体类class
     */
    private final Class<T> clazz;


    public EsIndexOperate(IndexCoordinates index,
                          Class<T> clazz,
                          ElasticsearchRestTemplate elasticsearchRestTemplate,
                          RestHighLevelClient client) {
        this.index = index;
        this.indexOperations = elasticsearchRestTemplate.indexOps(index);
        this.clazz = clazz;
        this.client = client;
    }


    /**
     * 索引是否存在
     *
     * @return boolean
     */
    public boolean exists() {
        return indexOperations.exists();
    }

    /**
     * 如果索引不存在则创建索引
     */
    public void createIfExists() {
        // 校验索引是否存在
        boolean exists = indexOperations.exists();
        if (!exists) {
            log.info("索引{}不存在，开始创建索引", index.getIndexName());
            Map<String, Object> setting = new HashMap<>();
            setting.put(EsConstant.MAX_RESULT_WINDOW_FIELD, EsConstant.MAX_RESULT_WINDOW);
            setting.put(EsConstant.SHARDS_FIELD, EsConstant.SHARDS);
            setting.put(EsConstant.REPLICAS_FIELD, EsConstant.REPLICAS);
            indexOperations.create(setting);
            indexOperations.putMapping(clazz);
        }
    }

    /**
     * 更新mapping
     */
    public void updateMapping() {
        indexOperations.putMapping(clazz);
    }

    /**
     * 更新设置
     *
     * @param settings setting
     */
    public void updateSetting(Settings settings) {
        UpdateSettingsRequest request = new UpdateSettingsRequest(index.getIndexNames())
                .settings(settings);
        try {
            client.indices().putSettings(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            throw new ElasticsearchException("更新设置失败，原因：" + e.getMessage(), e);
        }
    }


    /**
     * 新增别名
     *
     * @param alias 别名
     */
    public void addAlias(String alias) {
        AliasActionParameters parameters = AliasActionParameters.builder()
                .withAliases(alias)
                .withIndices(index.getIndexName())
                .build();
        AliasActions add = new AliasActions()
                .add(new AliasAction.Add(parameters));
        indexOperations.alias(add);
    }

    /**
     * 删除别名
     *
     * @param alias 别名
     */
    public void deleteAlias(String alias) {
        AliasActionParameters parameters = AliasActionParameters.builder()
                .withAliases(alias)
                .withIndices(index.getIndexName())
                .build();
        AliasActions remove = new AliasActions().add(new AliasAction.Remove(parameters));
        indexOperations.alias(remove);
    }

    /**
     * 获取索引名称
     *
     * @return 索引名称集合
     */
    public List<String> getIndexesName() {
        List<IndexInformation> information = this.getInformation();
        return information.stream()
                .map(IndexInformation::getName)
                .collect(Collectors.toList());
    }

    /**
     * 获取索引名称
     *
     * @return 索引名称集合
     */
    public List<String> getIndexesAliases() {
        List<IndexInformation> information = this.getInformation();
        return information.stream()
                .map(IndexInformation::getAliases)
                .filter(Objects::nonNull)
                .flatMap(Collection::stream)
                .map(AliasData::getAlias)
                .collect(Collectors.toList());
    }


    /**
     * 删除索引
     */
    public void deleteIndex() {
        indexOperations.delete();
    }


    /**
     * 获取索引信息
     *
     * @return 索引信息
     */
    private List<IndexInformation> getInformation() {
        return indexOperations.getInformation();
    }
}
